package com.zzw.distributedlock;

import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;

public class ZkLock {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public boolean tryLock(LockInfo info) {
        InterProcessMutex mutex = getMutex(info);
        int tryTimes = info.getTryTimes();
        long tryInterval = info.getTryInterval();
        boolean flag = true;// 代表是否需要重试
        while (flag && --tryTimes >= 0) {
            try {
                if (mutex.acquire(info.getWaitLockTime(), TimeUnit.MILLISECONDS)) {
                    logger.info(LogConstant.DST_LOCK + "acquire lock successfully!");
                    flag = false;
                    break;
                }
            } catch (Exception e) {
                logger.error(LogConstant.DST_LOCK + "acquire lock error!", e);
            } finally {
                checkAndRetry(flag, tryInterval, tryTimes);
            }
        }
        return !flag;// 最后还需要重试，说明没拿到锁
    }

    public boolean releaseLock(LockInfo info) {
        InterProcessMutex mutex = getMutex(info);
        int tryTimes = info.getTryTimes();
        long tryInterval = info.getTryInterval();
        boolean flag = true;// 代表是否需要重试
        while (flag && --tryTimes >= 0) {
            try {
                mutex.release();
                logger.info(LogConstant.DST_LOCK + "release lock successfully!");
                flag = false;
                break;
            } catch (Exception e) {
                logger.error(LogConstant.DST_LOCK + "release lock error!", e);
            } finally {
                checkAndRetry(flag, tryInterval, tryTimes);
            }
        }
        return !flag;// 最后还需要重试，说明没拿到锁
    }

    private synchronized InterProcessMutex getMutex(LockInfo info) {
        InterProcessReadWriteLock lock = null;
        /*if (locksCache.get(info.getLock()) != null) {
            lock = locksCache.get(info.getLock());
        } else {
            lock = new InterProcessReadWriteLock(client, BASE_DIR + info.getLock());
            locksCache.put(info.getLock(), lock);
        }
        InterProcessMutex mutex = null;
        switch (info.getIsolate()) {
            case READ:
                mutex = lock.readLock();
                break;
            case WRITE:
                mutex = lock.writeLock();
                break;
            default:
                throw new IllegalArgumentException();
        }*/
        return lock.writeLock();
    }

    private void checkAndRetry(boolean flag, long tryInterval, int tryTimes) {
        try {
            if (flag) {
                Thread.sleep(tryInterval);
                logger.info(LogConstant.DST_LOCK + "retry getting lock! now retry time left: " + tryTimes);
            }
        } catch (InterruptedException e) {
            logger.error(LogConstant.DST_LOCK + "retry interval thread interruptted!", e);
        }
    }
}
